<!doctype html>
<html lang="zh-cn">
<head>

    <meta charset="utf-8">
    <meta name="generator" content="Hugo 0.57.2" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Java多线程 | The Sky of OtsWang</title>
    <meta property="og:title" content="Java多线程 - The Sky of OtsWang">
    <meta property="og:type" content="article">
        
    <meta property="article:published_time" content="2018-12-19T11:05:18&#43;08:00">
        
        
    <meta property="article:modified_time" content="2019-04-08T16:24:44&#43;08:00">
        
    <meta name="Keywords" content="golang,go语言,otswang,java,博客,python">
    <meta name="description" content="Java多线程">
        
    <meta name="author" content="OtsWang">
    <meta property="og:url" content="https://otswang.gitee.io/hugo/post/java/multithread/">
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">

    <link rel="stylesheet" href="/hugo/css/normalize.css">
    
        <link rel="stylesheet" href="/hugo/css/prism.css">
    
    <link rel="stylesheet" href="/hugo/css/style.css">
    <script type="text/javascript" src="//cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>

    


    
    
</head>

<body>
<header id="header" class="clearfix">
    <div class="container">
        <div class="col-group">
            <div class="site-name ">
                
                    <a id="logo" href="https://otswang.gitee.io/hugo/">
                        The Sky of OtsWang
                    </a>
                
                <p class="description">擅长写HelloWorld的小小码农</p>
            </div>
            <div>
                <nav id="nav-menu" class="clearfix">
                    
                    
                    <a  href="https://otswang.gitee.io/hugo/" title="Home">Home</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/tags/" title="Tags">Tags</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/categories/" title="Categories">Categories</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/archives/" title="Archives">Archives</a>
                    
                    <a  href="https://otswang.gitee.io/hugo/about/" title="About">About</a>
                    
                </nav>
            </div>
        </div>
    </div>
</header>


<div id="body">
    <div class="container">
        <div class="col-group">

            <div class="col-8" id="main">
                <div class="res-cons">
                    <article class="post">
                        <header>
                            <h1 class="post-title">Java多线程</h1>
                        </header>
                        <date class="post-meta meta-date">
                            2018年12月19日
                        </date>
                        
                        <div class="post-meta">
                            <span>|</span>
                            
                                <span class="meta-category"><a href="https://otswang.gitee.io/hugo/categories/java">Java</a></span>
                            
                        </div>
                        
                        
                        
                        <div class="post-content">
                            <p>多线程，对cpu资源的合理利用。
对Java线程安全的定义为：当多个线程访问同一个类时，如果不用考虑这些线程在运行时环境下的调度和交替运行，并且不需要额外的同步及在调用方式代码不必做其他的协调，这个类任然是正确的，那么这个类就是线程安全的。显然只有在存在资源竞争时才会导致线程不安全，因此，无状态的对象永远是线程安全的。</p>

<h2 id="概览">概览</h2>

<p><a href="https://www.draw.io/?lightbox=1&amp;highlight=0000ff&amp;edit=_blank&amp;layers=1&amp;nav=1&amp;title=Java%E7%BA%BF%E7%A8%8B.xml#R7Vtbc%2BI2FP41mmkfkrEtX%2BRHA862M%2B3utulOt33pCFuAN8JihFggv76SkW2MDMkmLJglmcxEPrpYOud852YFwP509Y7j2eR3lhIKHCtdATgAjmO7ji%2F%2FKMp6Q0Ew3BDGPEv1oJpwnz0STbQ0dZGlZN4YKBijIps1iQnLc5KIBg1zzpbNYSNGm2%2Bd4TExCPcJpib17ywVE30KJ6jpv5BsPCnfbPv6fFNcDtYnmU9wypZbJBgD2OeMiU1ruuoTqphX8mUz725Pb7UxTnLxnAmjdfzX4ycnZB%2Fe%2FTENEUb%2F%2FRvdwM0qXzFd6APfC8zFTz%2FrPYt1yQiSSr7oR8bFhI1ZjmlcU3ucLfKUqLdZ8mkiplQ2bdn8QoRYa9HihWCSVK%2FwG2MzPW7zTvWivUfUpDlb8IQcOFepKpiPiTgwzqkEITWYsCkRfC3ncUKxyL4294G1Ko2rcTW3ZUMz%2FBuYbxvMf0%2BWJuMplcquGLycZILcz3Bx8qXEW5PNo4zSPqOMF%2FPgaDRykkTS54KzB7LVk%2FpD3%2FMrhn8lXJDVYZabLNITkNZuDe9APy5rrNglACZbOCmnHZ%2Bn7kHNzVl%2BUFXJKhOft9r%2F6CGSG3z9efuh6Ln1vkG95wpZkbJJkpBQPJ9nSUm%2By2i1hTwtB%2BndSorut46LEueZKEHnRInjGDD5wrJcmqjYBT0EogGIfRD6qrEreqnXoilgTubZIx4WAxQ3Z3IpUWzZ6wFvICmYZuNcSUiyk0jE9BQ%2BMukRIt0xzdK0MHgUDwnt4eRhXOhTE3vy5xDCtL%2FSO6m9xLYYDyj4XjxatxC5qIHJ0sg%2FW1x68Y%2BKNfXKN64r1X17YTtorsFGo7nUo12BV5t8hQ6YfmpOCZkpJQhArwdCWCjBAIR3b0oglcALbL%2BpBN7rlGDdOuE7Stw1JP6rXOgDiD0QxQD1lbwRAqH1Jm%2Fnxrp1ob%2BDevt1Av%2F%2BIi419DSu%2Bjxx6HM97B75nigORQbWQIwAikEvUHhDd9K99j9%2Bugqk%2BU8hzfY8p%2BkGuw40M4D6c5HnBW%2BOlWykmKBRa7LhJ4gMD8rqxcmGA8%2BdbQQGZ%2FkibwtJfKqAMuSyNVYtBateHyCnaCD1G4dA7lP%2BKsTJFaKWWZedlLvPNIZ7IHgaYxiatnCX65fI0%2FOmcJbBVJ3CXYFHCZ9yKDKP2onVnc57FM8QaJmPXb1EZSzuhmHXJWibxccfws7ZVrtwTmTofBMX6zyZcJZLbqXXAA77cAinUtXQbdq77ps7M85b4qztK8n1CVT6L%2BS5DXm6r5PnqqEVVTkDltXHE8i7LSEOVVSOoiKod0EvVhTZQPabEiifF3gXBmrbMwT32vJT132jc1bfaGZWV%2Bcbvad8IwzK%2BxGXU8YNjoIjawdHVRm3ergAhJ0VYLYJsHVGaHolYUrwVJhi%2BZ3PysyPXqpSm%2BVjE2IvLdR6BKVuW6EWOUPoH%2BlWSPcqtbb5Bbn4gmiDqKjBRjKSG2yFdLul1%2FdMZKO1gtLdphlRqp52x2UKHIuZaOs7aCe7X74tr%2BR1PM6wzWKjqshHA4DCotoeA%2BSZwulRljyoMORpqb0QekOcoBS2Qc%2BBruulx4GeHTShB8NzQw%2Ban%2BhfFCAUl61aQwTddeYgwXZOFCUUUyPO8XprgHbYe9NpN2zqhWftXBfdGW%2B7B8fLxmYHR%2FV%2FsKUqKSErt7658CFBHHm1lTZz8isIdOCeCmcV6FjQsxui634K4bSIvRJyceEnbPkc%2BqOYbBd2zWSb9a%2BK15fF2bpq2JULyuYXggHBx%2BPrCCWk%2Fdb3EHmuZx2JryeM7%2BVj%2FU8SG4tT%2F6sJjP8H">Java线程的状态</a></p>

<p>synchronized, wait, notify 是任何对象都具有的同步工具。Java中的每个对象都有一个监视器(monitor)，来监测并发代码的重入。在非多线程编码时该监视器不发挥作用，反之如果在synchronized 范围内，监视器发挥作用。
wait和notify必须存在于synchronized代码块中，并且这三个对象针对同一个监视器(某对象的监视器)。</p>

<ul>
<li><p>synchronized单独使用：
在多线程环境下，synchronized块中的方法获取了lock实例的monitor，如果实例相同，那么只有一个线程能执行该块内容</p>

<pre><code class="language-JAVA">public class Thread1 implements Runnable {
Object lock;
public void run() {  
    synchronized(lock){
        ..do something
    }
}
}
</code></pre></li>

<li><p>直接用于方法：
相当于上面代码中用lock来锁定的效果，实际获取的是Thread1类的monitor。更进一步，如果修饰的是static方法，则锁定该类所有实例。</p>

<pre><code class="language-JAVA">public class Thread1 implements Runnable {
public synchronized void run() {  
    ..do something
}
}
</code></pre></li>
</ul>

<p><strong>理解：</strong></p>

<p>synchronized可以多线程安全，主要是因为monitor只允许一个活动线程在其中，而synchronized后的实例如果不变的话，则就只有一个monitor。</p>

<p>多线程的内存模型分为：主存（main memory）和线程栈（working memory）。处理数据时，线程会把数据从主存复制到线程栈，完成操作后再save回去。</p>

<h2 id="volatile关键字">volatile关键字</h2>

<p><a href="https://www.draw.io/?lightbox=1&amp;highlight=0000ff&amp;edit=_blank&amp;layers=1&amp;nav=1&amp;title=Java%E7%BA%BF%E7%A8%8B.xml#R5VjLcpswFP0aLdsxT4uln%2BkimbbjdNp001HgGtTKiBFybOfrK4EwYIiTtHHqSVfoHokrdM7RC%2BRMVtsLQbLkikfAkD2ItsiZItu2XNtXD43sSgQ7QQnEgkamUQ0s6D0YcGDQNY0gbzWUnDNJszYY8jSFULYwIgTftJstOWv3mpEYOsAiJKyLfqWRTMwo7GGNfwAaJ6ZnDztlxYpUbc1A8oREfNOAnBlyJoJzWZZW2wkwzV1Fy3I3u77%2FYgf848XnVYAJ%2FvF99K5MNn%2FOK%2FsRCEjly6Y2Y70jbG3ouiI0VcgVrLjYqQKazdF4gjBOgGRVYByQy13FsuDrNALd1QA5401CJSwyEurajfKVwhK5YiqyVHHJU2mMYrk6poxNOOOiyOVEBPAyVHguBf8FjRo%2FxHC7VDXms0FI2B7I%2FAhJ1l455XjgK5DFMKssAyN2ZXYTbmrneL7BkoZrhgYjxqzxPnOtiCoYUZ4hkNsR6JKTSOui0tqDBbmDl9XitZi1vH9Nrdeh9joRUJBrndbfHuDI7fM3tm8d3z%2BlCnZbhT27DRWCHhEs91Qq%2BA%2BrYL9VFfasn40Kw44Kb5V713Lee2fGPv5v2Pfcc3N%2B8Dj3kEYjfRBVUchIntPwON2KILH7pqVSTjPhjVEOtlQ2qlR0Y7KU3ULUOc0%2BhXD1vXwtQjjWzjAoiYjhWEKvX8HmPt2jUIUJYETSu%2FYg%2BlQzPXziVA2v3qD8g2OCfyB8OU7zVvO4e5Bof%2F%2BoElkHiUoeOokKE%2B2H%2Fee%2BsrpnCK3twoQpT9Vj3J7WDU8d81CuPl1WjjSJCmxO9TeWPuvzrAJNE93FT5ByZ3xL1pIriAuZ8JinhF1ynj1kb2Nh61wN7Pcb%2BG%2BdebBpd5akB5z5YoYaPGGlYkxdq%2BHxHYLkWXnXXtKttt%2FrXQPc9uYbeJ313%2B1ZXU62%2FFt2h9U7rn2iKJ0NUTBC2EUzF42nKJgUiItGuLoHK8RH4zlS18SZh%2FAcBVbRGBeIj0YTNLJYeWHL9VVNYYGD8LROeSih4lu2tRKQ03tyWzTQUzvTDit48MbIm2o11ezNjXg6ZDROVZnBUqfSItKQsJGBpZ7Z41x5g6bxdTHN37mvaAHPaU8kN7A7HrD7boL2802gwvoHTTkT679czuw3">volatile图示</a></p>

<p>针对多线程使用的变量如果不是volatile或者final修饰的，很有可能产生不可预知的结果（另一个线程修改了这个值，但是之后在某线程看到的是修改之前的值）。其实道理上讲同一实例的同一属性本身只有一个副本。<strong>但是多线程是会缓存值的</strong>，本质上，volatile就是不去缓存，直接取值。在线程安全的情况下加volatile会牺牲性能。</p>

<h2 id="主要工具">主要工具</h2>

<h3 id="threadlocal">ThreadLocal</h3>

<p>ThreadLoal 变量，它的基本原理是，同一个 ThreadLocal 所包含的对象（对ThreadLocal&lt; String &gt;而言即为 String 类型变量），在不同的 Thread 中有不同的副本（实际是不同的实例）。</p>

<p><a href="https://www.cnblogs.com/jasongj/p/8079718.html">https://www.cnblogs.com/jasongj/p/8079718.html</a></p>

<h3 id="原子类">原子类</h3>

<h3 id="lock">Lock</h3>

<h3 id="容器类">容器类</h3>

<ul>
<li>BlockingQueue</li>
<li>ConcurrentHashMap</li>
</ul>

<h3 id="管理类">管理类</h3>

<p><a href="https://www.cnblogs.com/sheeva/p/6366782.html">JVM视角下的多线程</a></p>

<h2 id="深入浅出java-concurrent-学习">深入浅出Java concurrent 学习</h2>

<p><a href="http://www.blogjava.net/xylz/archive/2010/07/08/325587.html">对j.U.C的学习</a></p>

<p><a href="https://www.draw.io/?lightbox=1&amp;highlight=0000ff&amp;edit=_blank&amp;layers=1&amp;nav=1&amp;title=Java%E7%BA%BF%E7%A8%8B.xml#R7Vxdc5s4FP01eWwHEJ%2BPDXF3p5PubONm2zwqIBsagRhZxPb%2B%2BhVGNthyE3sxyFH8FLhIwjr3HEn3SuQKhNniDwqL5CuJEb6yjHhxBW6uLMt0fIP%2FqSzL2hIEQW2Y0jQWhRrDOP0XCaOoNy3TGM22CjJCMEuLbWNE8hxFbMsGKSXz7WITgrffWsApkgzjCGLZ%2BiONWSKsphs0D%2F5E6TQRr%2FYtr36QwXVh0ZNZAmMyb5nA6AqElBBWX2WLEOEKvDUun77cP7Db5K9%2F0mx%2Bc3f9YH77%2FuFD3djnY6psukBRzk7btFM3%2FQxxKfASfWXLNYAo5niKW0JZQqYkh3jUWK8pKfMYVa8x%2BF3CMswvTX75CzG2FJSAJSPc1LRwS0ghytXvrF6047NXOizKzUhJI%2FRCOSB4B%2BkUvdSevfEqlwMiGWJ0yetRhCFLn7d%2FHBS8nG7KNdjzCwH%2FEa7wLq5olXNVuiI4C1egRcp%2BVtU%2FOuLuQTR2Lk7yVTrJNC9eOshLpqHSTUDy0pf7UHJU44YK03mSMjQu4Kr7c74u2XbNJMU4JJjQVV0QQ%2BRPIm6fMUqeUOuJG%2FnocbJxxTOiDC3%2BhzNk7EQrti3WBmJxBBzwUUyp89ZiY72CSFrrDNfoSxeGhDgm0dPspJhPJsiN9mIee8GjYfSI%2BQY5gbllqsfclyCv1rjaQO6C84McmBK6HUb7%2FaP46knOf%2B1PUWN187Apdy6LKvfAmcDquqpaVf1EKVy2ChQkzdms1fLflaFhj2Nss8cxrbb3pfLA7Vje8XbYVf%2FihmubrnegH7jQ72j6Oe%2BBfq4xBP3sC%2F2Opp%2F3Lug3yOjnXOh3NP26Rstvgn6eYQ1AP%2FdCv6PpF7wL%2Bjn2APTzLvQ7ln6gaxLqbdAvGIB%2BAvJWsgEtUMQ5QCVavtF8w25azQaO8nyDKed4TjkKHJxu%2Fs2Y4DkDiN0%2BUOxm15V2J09Z9ll76pwcZQGVjpL9FBGMUcRSkuuTOz3DLQJL3pQJSR6VtOrpV47lKbGPHeTH9j7sfesRuG6P2Pu784i7D%2FtgD%2FSgt2lE3ub%2FViJ%2BqSnk%2B7cKhoXckiCHhGVppMsQw5e5ZzfEmPIQo2IS7nuiPXgP3uo40e6PP6T9Z9%2FebqLugKj1UiBj7cjW21Bo3VTdR6mpU0U1lnwU7XPJSqrNyAj8ndgysNSOi5YcSIYQY%2FiI9cXcVo25PP2P%2BgjezwhzVznmcuQekqzAqIozxog%2Bp5G2hHd9T14IgEHRlw9T3qFfPMhDcc187oQE5jFG2irAA4HsBHdIJ6wbbjnhe5qh%2Bzxl2oLuyaAPOuzY%2FWzRt%2FYIxI7BG9glWJ9JfH2bQOmRYiDPFHcIxj8o18AtiZ500YrlbWtlExoq00o%2FG7qaa6Xrjm43rcjzeiWRcVkUHDZtleKpVspJ0yjvRCm20i8gbHnxpfNkAlQrpJ%2BTuZor5Dc%2BHkgh8qdcIcnjtIoNdZWJr1gmTnCRyc7nO6%2BrROm5BlvOHY5RBouE6JMk3%2F3SyPfVqmSdpbmo5AiVKI3hbTmGX2fYT3um5IxUYlqKc13OJX4%2FXiZKw3dbDt9D7g92Q%2Bb5LWRRoqtWFB9Gcfo5O661Uhyl4bsjh%2B%2FhMsJpdA0pTfXZtdoVyjonq2zp1c8H3norpesXtt2UIh%2FhGS2iBOZTfVXSY0KY3zb%2FXKw%2BZtX8izYw%2Bg8%3D">juc脑图</a></p>

<h2 id="原子操作">原子操作</h2>

<p>原子操作的的描述为：**多个线程执行一个操作，其中任何一个线程要么完全执行完此操作，要么没有执行此操作的任何步骤，那么这个操作就是原子的。</p>

<p>JVM线程内部维持顺序化语义，会发生指令重排（意义在于JVM能够根据处理器的特性，适当的重新排序机器指令，使机器指令能更符合CPU的执行特点，最大限度的发挥机器的性能）。</p>

<p>JMM动作（Java Memory Model Action）：Java 存储模型动作，一个动作包括：变量d读写、监视器的加锁和释放锁，线程的start() 和 Join()，以及锁等。</p>

<p>happens-before完整规则：</p>

<p>（1）同一个线程中的每个Action都happens-before于出现在其后的任何一个Action。</p>

<p>（2）对一个监视器的解锁happens-before于每一个后续对同一个监视器的加锁。</p>

<p>（3）对volatile字段的写入操作happens-before于每一个后续的同一个字段的读操作。</p>

<p>（4）Thread.start()的调用会happens-before于启动线程里面的动作。</p>

<p>（5）Thread中的所有动作都happens-before于其他线程检查到此线程结束或者Thread.join（）中返回或者Thread.isAlive()==false。</p>

<p>（6）一个线程A调用另一个另一个线程B的interrupt（）都happens-before于线程A发现B被A中断（B抛出异常或者A检测到B的isInterrupted（）或者interrupted()）。</p>

<p>（7）一个对象构造函数的结束happens-before与该对象的finalizer的开始</p>

<p>（8）如果A动作happens-before于B动作，而B动作happens-before与C动作，那么A动作happens-before于C动作。</p>

<p>public final void join()throws InterruptedException: Waits for this thread to die.</p>

<p>对join的学习：</p>

<pre><code class="language-java">public class JoinTest implements Runnable{

    private String name;

    public JoinTest(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.printf(&quot;%s begins: %s\n&quot;, name, new Date());
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.printf(&quot;%s end: %s\n&quot;, name, new Date());
    }

    public static void main(String[] args){
        long now = System.currentTimeMillis();
        Thread thread1 = new Thread(new JoinTest(&quot;one&quot;));
        Thread thread2 = new Thread(new JoinTest(&quot;two&quot;));
        thread1.start();
        thread2.start();

        try {
            thread1.join(2000);
            thread2.join(2000);
        } catch (InterruptedException e){
            e.printStackTrace();
        }
        System.out.println(&quot;time: &quot; + (System.currentTimeMillis() - now));
        System.out.println(&quot;main thread end.&quot;);

    }
}

/**
 * one begins: Thu Dec 20 16:32:45 CST 2018
 * two begins: Thu Dec 20 16:32:45 CST 2018
 * time: 4000
 * main thread end.
 * one end: Thu Dec 20 16:32:49 CST 2018
 * two end: Thu Dec 20 16:32:49 CST 2018
 */
</code></pre>

<p>volatile包含以下语义：</p>

<ul>
<li><p>Java 存储模型不会对valatile指令的操作进行<strong>重排序</strong>：这个保证对volatile变量的操作时按照指令的出现顺序执行的。</p></li>

<li><p>volatile变量不会被缓存在<strong>寄存器</strong>中（只有拥有线程可见）或者其他对CPU不可见的地方，每次总是从主存中读取volatile变量的结果。也就是说对于volatile变量的修改，其它线程总是可见的，并且不是使用自己线程栈内部的变量。也就是在happens-before法则中，对一个valatile变量的写操作后，其后的任何读操作理解可见此写操作的结果。</p></li>
</ul>

<p>应用volatile变量的三个原则：</p>

<ul>
<li>写入变量不依赖此变量的值，或者只有一个线程修改此变量</li>
<li>变量的状态不需要与其它变量共同参与不变约束</li>
<li>访问变量不需要加锁</li>
</ul>

<p>在JDK 5之前Java语言是靠synchronized关键字保证同步的，这会导致有锁。</p>

<p>锁机制存在以下问题：</p>

<ul>
<li>在多线程竞争下，加锁、释放锁会导致比较多的上下文切换和调度延时，引起性能问题。</li>
<li>一个线程持有锁会导致其它所有需要此锁的线程挂起。</li>
<li>如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置，引起性能风险。</li>
</ul>

<p>独占锁是一种悲观锁，synchronized就是一种独占锁，会导致其它所有需要锁的线程挂起，等待持有锁的线程释放锁。而另一个更加有效的锁就是乐观锁。所谓乐观锁就是，每次不加锁而是假设没有冲突而去完成某项操作，如果因为冲突失败就重试，直到成功为止。</p>

<p>乐观锁用到的机制就是CAS，Compare and Swap。
CAS有3个操作数，内存值V，旧的预期值A，要修改的新值B。当且仅当预期值A和内存值V相同时，将内存值V修改为B，否则什么都不做。</p>

<p>CAS是英文单词Compare And Swap的缩写，翻译过来就是比较并替换。CAS机制当中使用了3个基本操作数：</p>

<p>（1）内存地址V，也就是AtomicInteger中的valueOffset。</p>

<p>（2）旧的预期值A，也就是getAndIncrement方法中的current。</p>

<p>（3）要修改的新值B，也就是getAndIncrement方法中的next。</p>

<p>CAS机制中，更新一个变量的时候，只有当变量的预期值A和内存地址V当中的实际值相同时，才会将内存地址V对应的值修改为B。下面我们来看一个具体的例子：</p>

<ol>
<li>在内存地址V当中，存储着值为10的变量。</li>
<li>此时线程1想要把变量的值增加1。对线程1来说，旧的预期值A=10，要修改的新值B=11。</li>
<li>但是，在线程1要提交更新之前，另一个线程2抢先一步，把内存地址V中的变量值率先更新成了11。</li>
<li>此时，线程1开始提交更新，首先进行A和地址V的实际值比较（Compare），发现A不等于V的实际值，提交失败。</li>
<li>线程1重新获取内存地址V的当前值，并重新计算想要修改的新值。此时对线程1来说，A=11，B=12。这个重新尝试的过程被称为自旋。</li>
<li>这一次比较幸运，没有其他线程改变地址V的值。线程1进行Compare，发现A和地址V的实际值是相等的。</li>
<li>线程1进行替换，把地址V的值替换为B，也就是12。</li>
</ol>

<p>对比Synchronized，我们可以发现，Synchronized属于悲观锁，悲观地认为程序中的并发情况严重，所以严防死守。CAS属于乐观锁，乐观地认为程序中的并发情况不那么严重，所以让线程不断去尝试更新。</p>

<h2 id="线程安全的实现方法">线程安全的实现方法</h2>

<ul>
<li>互斥同步： （临界区、互斥量和信号量是实现互斥的主要形式）</li>
<li>synchronized 关键字。编译后的synchronized 关键字在代码块前后形成 <code>monitor enter</code> 和 <code>monitor exit</code>这两个字节码指令。</li>
<li>还可使用 java.uitl.concurrent包中的重入锁(reentrantlock)来实现同步。</li>
<li>非阻塞同步： 基于冲突检测的乐观并发策略。</li>
<li>无同步方案：可重入代码，在代码执行的任意时刻中断它，转而去执行另外的一段代码。</li>
</ul>

<h2 id="synchronized-关键字"><code>synchronized</code>关键字</h2>

<p>Java中每一个对象都可以作为锁，这是synchronized实现同步的基础：</p>

<ul>
<li>普通同步方法，锁是当前实例对象</li>
<li>静态同步方法，锁是当前类的class对象</li>
<li>同步方法块，锁是括号里面的对象</li>
</ul>

<p>对于同步方法，JVM采用ACC_SYNCHRONIZED标记符来实现同步。 对于同步代码块。JVM采用monitorenter、monitorexit两个指令来实现同步</p>

<p><a href="https://img-blog.csdnimg.cn/20181220172156851">https://img-blog.csdnimg.cn/20181220172156851</a></p>

<p>synchronized与原子性： 通过加锁将操作原子化。</p>

<p>synchronized与可见性： 修改后立即可见。变量在解锁之前，必须将数据同步到主内存，保证可见。</p>

<pre><code>synchronized其实是借助Monitor实现的，在加锁时会调用objectMonitor的enter方法，解锁的时候会调用exit方法。事实上，只有在JDK1.6之前，synchronized的实现才会直接调用ObjectMonitor的enter和exit，这种锁被称之为重量级锁。

所以，在JDK1.6中出现对锁进行了很多的优化，进而出现轻量级锁，偏向锁，锁消除，适应性自旋锁，锁粗化(自旋锁在1.4就有，只不过默认的是关闭的，jdk1.6是默认开启的)，这些操作都是为了在线程之间更高效的共享数据 ，解决竞争问题。

锁主要存在四中状态，依次是：无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态，他们会随着竞争的激烈而逐渐升级。注意锁可以升级不可降级，这种策略是为了提高获得锁和释放锁的效率。

--------------------- 
作者：Franco蜡笔小强 
来源：CSDN 
原文：https://blog.csdn.net/w372426096/article/details/81624905 
版权声明：本文为博主原创文章，转载请附上博文链接！
</code></pre>

<h2 id="悲观锁与乐观锁">悲观锁与乐观锁</h2>

<p>悲观锁： 默认会发生不一致，所以提前加上锁来实现一致性；</p>

<p>乐观锁： 默认不会发生数据冲突，所以不用加锁，使用cas来进行数据更新。</p>

<p>这两种锁更多的是一种思想，而不是具体的锁实现。下面以SQL来进行对比：</p>

<p><strong>不加锁</strong></p>

<pre><code class="language-sql">update tbl_product set stock = 3 where id = 4;
</code></pre>

<p>如果上面的SQL同时被两个线程执行，则会导致数据修改的失败。</p>

<p><strong>悲观锁</strong></p>

<pre><code class="language-sql">begin;
select stock from tbl_product where id = 4 for update;
-- for update 会造成加锁
update tbl_product set stock = 3 where id = 4;
commit;
</code></pre>

<p><strong>乐观锁</strong></p>

<pre><code class="language-sql">select stock from tbl_prodct where id = 4;  -- result = 4
update tbl_product set stock = 3 where id = 4 and stock = 4;
</code></pre>

<p>当数据发生不一致时，数据更新会失败。</p>

<p>缺点： 当大并发时，会造成数据大量更新失败。并且无法消除<strong>aba</strong>问题。</p>

<p><strong>ABA问题</strong></p>

<p>当有两个线程A与B，A将stock修改为3，然后又修改为4，而当B进行修改前获取的stock为4，当进行修改时，任然为4，但是中间发生了其他的变化。虽然stock修改没有出现冲突，但是 ？</p>

<p><strong>修改的乐观锁</strong></p>

<p>使用每次修改都递增的字段进行判断</p>

<pre><code class="language-sql">-- 线程A
select version from tbl_product where id = 4; -- result = 5
-- 线程B
select version from tbl_product where id = 4; -- result = 5
update tbl_product set stock = 3 , version = 6 where id = 4 and version = 5;
select version from tbl_product where id = 4; -- result = 6
update tbl_product set stock = 4 , version = 7 where id = 4 and version = 6;
-- 线程A
update tbl_product set stock = 3 , version = 6 where id = 4 and version = 5;        -- 失败
</code></pre>

<p><strong>再次修改</strong></p>

<p>通过分析业务，对SQL进行如下的修改</p>

<pre><code class="language-sql">-- 修改商品库存
update tbl_product set stock=stock - 1 where id = 4 and stock - 1 &gt; 0
</code></pre>

<h2 id="偏向锁-轻量级锁和重量级锁以及锁优化">偏向锁、轻量级锁和重量级锁以及锁优化</h2>

<p>当同步代码块大部分都是只被一个线程访问时，可以将锁改为偏向锁以提高性能。（此时是JVM自动调整）。</p>

<p>当同步代码块不再只被一个线程访问，同时同步代码块执行速度非常快时，可以使用强轻量级锁来优化。（类似于乐观锁）</p>

<p>当同步代码块执行速度非常慢时，只能使用重量级锁来完成同步任务。</p>

<h2 id="线程池">线程池</h2>

<h3 id="线程池参数">线程池参数</h3>

<pre><code class="language-java">java.util.concurrent.ThreadPoolExecutor#ThreadPoolExecutor：
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue&lt;Runnable&gt; workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize &lt; 0 || maximumPoolSize &lt;= 0 || maximumPoolSize &lt; corePoolSize || keepAliveTime &lt; 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.acc = System.getSecurityManager() == null ? null : AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}
</code></pre>

<p>创建线程池一共有7个参数，从源码可知，corePoolSize和maximumPoolSize都不能小于0，且核心线程数不能大于最大线程数。</p>

<ul>
<li>corePoolSize</li>
</ul>

<p>线程池核心线程数量，核心线程不会被回收，即使没有任务执行，也会保持空闲状态。</p>

<ul>
<li>maximumPoolSize</li>
</ul>

<p>池允许最大的线程数，当线程数量达到corePoolSize，且workQueue队列塞满任务了之后，继续创建线程。</p>

<ul>
<li>keepAliveTime</li>
</ul>

<p>超过corePoolSize之后的“临时线程”的存活时间。</p>

<ul>
<li>unit</li>
</ul>

<p>keepAliveTime的单位。</p>

<ul>
<li>workQueue</li>
</ul>

<p>当前线程数超过corePoolSize时，新的任务会处在等待状态，并存在workQueue中，BlockingQueue是一个先进先出的阻塞式队列实现，底层实现会涉及Java并发的AQS机制。</p>

<ul>
<li>threadFactory</li>
</ul>

<p>创建线程的工厂类，通常我们会自定义一个threadFactory设置线程的名称，这样我们就可以知道线程是由哪个工厂类创建的，可以快速定位。</p>

<ul>
<li>handler</li>
</ul>

<p>线程池执行拒绝策略，当线程数量达到maximumPoolSize大小，并且workQueue也已经塞满了任务的情况下，线程池会调用handler拒绝策略来处理请求。系统默认的拒绝策略有以下几种：</p>

<p>AbortPolicy：为线程池默认的拒绝策略，该策略直接抛异常处理。<br />
DiscardPolicy：直接抛弃不处理。<br />
DiscardOldestPolicy：丢弃队列中最老的任务。<br />
CallerRunsPolicy：将任务分配给当前执行execute方法线程来处理。</p>

<h3 id="问题">问题</h3>

<p>现有一个线程池，参数corePoolSize = 5，maximumPoolSize = 10，BlockingQueue阻塞队列长度为5，此时有4个任务同时进来，问：线程池会创建几条线程？
如果4个任务还没处理完，这时又同时进来2个任务，问：线程池又会创建几条线程还是不会创建？
如果前面6个任务还是没有处理完，这时又同时进来5个任务，问：线程池又会创建几条线程还是不会创建？</p>

<p>线程池corePoolSize=5，线程初始化时不会自动创建线程，所以当有4个任务同时进来时，执行execute方法会新建【4】条线程来执行任务；<br />
前面的4个任务都没完成，现在又进来2个队列，会新建【1】条线程来执行任务，这时poolSize=corePoolSize，还剩下1个任务，线程池会将剩下这个任务塞进阻塞队列中，等待空闲线程执行；<br />
如果前面6个任务还是没有处理完，这时又同时进来了5个任务，此时还没有空闲线程来执行新来的任务，所以线程池继续将这5个任务塞进阻塞队列，但发现阻塞队列已经满了，核心线程也用完了，还剩下1个任务不知道如何是好，于是线程池只能创建【1】条“临时”线程来执行这个任务了；<br />
这里创建的线程用“临时”来描述还是因为它们不会长期存在于线程池，它们的存活时间为keepAliveTime，此后线程池会维持最少corePoolSize数量的线程。</p>

<h3 id="为什么不建议使用executors创建线程池">为什么不建议使用Executors创建线程池？</h3>

<p>JDK为我们提供了Executors线程池工具类，里面有默认的线程池创建策略，大概有以下几种：</p>

<p>FixedThreadPool：线程池线程数量固定，即corePoolSize和maximumPoolSize数量一样。<br />
SingleThreadPool：单个线程的线程池。<br />
CachedThreadPool：初始核心线程数量为0，最大线程数量为Integer.MAX_VALUE，线程空闲时存活时间为60秒，并且它的阻塞队列为SynchronousQueue，它的初始长度为0，这会导致任务每次进来都会创建线程来执行，在线程空闲时，存活时间到了又会释放线程资源。<br />
ScheduledThreadPool：创建一个定长的线程池，而且支持定时的以及周期性的任务执行，类似于Timer。</p>

<p>用Executors工具类虽然很方便，我依然不推荐大家使用以上默认的线程池创建策略，阿里巴巴开发手册也是强制不允许使用Executors来创建线程池，我们从JDK源码中寻找一波答案：</p>

<pre><code class="language-java">java.util.concurrent.Executors：
// FixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue&lt;Runnable&gt;());
}

// SingleThreadPool
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue&lt;Runnable&gt;()));
}

// CachedThreadPool
public static ExecutorService newCachedThreadPool() {
    // 允许创建线程数为Integer.MAX_VALUE
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue&lt;Runnable&gt;());
}

// ScheduledThreadPool
public ScheduledThreadPoolExecutor(int corePoolSize) {
    // 允许创建线程数为Integer.MAX_VALUE
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
复制代码public LinkedBlockingQueue() {
    // 允许队列长度最大为Integer.MAX_VALUE
    this(Integer.MAX_VALUE);
}
</code></pre>

<p>复制代码从JDK源码可看出，Executors工具类无非是把一些特定参数进行了封装，并提供一些方法供我们调用而已，我们并不能灵活地填写参数，策略过于简单，不够友好。</p>

<p>CachedThreadPool和ScheduledThreadPool最大线程数为Integer.MAX_VALUE，如果线程无限地创建，会造成OOM异常。
LinkedBlockingQueue基于链表的FIFO队列，是无界的，默认大小是Integer.MAX_VALUE，因此FixedThreadPool和SingleThreadPool的阻塞队列长度为Integer.MAX_VALUE，如果此时队列被无限地堆积任务，会造成OOM异常。</p>

<p>参考资料：</p>

<p>链接：<a href="https://juejin.im/post/5cae9b42f265da03705fa152">https://juejin.im/post/5cae9b42f265da03705fa152</a></p>

<h2 id="executor与threadpoolexecutor的使用">Executor与ThreadPoolExecutor的使用</h2>

<p>Java 并发编程第四章学习。</p>

<ul>
<li>AsynchronousChannelGroupImpl (sun.nio.ch)

<ul>
<li>Iocp (sun.nio.ch)</li>
</ul></li>
<li>ConcurrentExecutorAdapter (org.springframework.core.task.support)</li>
<li>DefaultExecutor in ServerImpl (sun.net.httpserver)</li>
<li>ExecutorService (java.util.concurrent)

<ul>
<li>AbstractExecutorService (java.util.concurrent)

<ul>
<li>AbstractEventExecutor (io.netty.util.concurrent)

<ul>
<li>AbstractEventLoop (io.netty.channel)</li>
<li>AbstractScheduledEventExecutor (io.netty.util.concurrent)

<ul>
<li>EmbeddedEventLoop (io.netty.channel.embedded)</li>
<li>GlobalEventExecutor (io.netty.util.concurrent)</li>
<li>SingleThreadEventExecutor (io.netty.util.concurrent)

<ul>
<li>DefaultEventExecutor (io.netty.util.concurrent)</li>
<li>SingleThreadEventLoop (io.netty.channel)

<ul>
<li>DefaultEventLoop (io.netty.channel)</li>
<li>NioEventLoop (io.netty.channel.nio)</li>
<li>ThreadPerChannelEventLoop (io.netty.channel)</li>
</ul></li>
</ul></li>
</ul></li>
<li>ImmediateEventExecutor (io.netty.util.concurrent)</li>
<li>NonStickyOrderedEventExecutor in NonStickyEventExecutorGroup (io.netty.util.concurrent)</li>
</ul></li>
<li>DelegatedExecutorService in Executors (java.util.concurrent)

<ul>
<li>DelegatedScheduledExecutorService in Executors (java.util.concurrent)</li>
<li>FinalizableDelegatedExecutorService in Executors (java.util.concurrent)</li>
</ul></li>
<li>ExecutorServiceAdapter (org.springframework.core.task.support)</li>
<li>ForkJoinPool (java.util.concurrent)</li>
<li>InlineExecutorService (org.apache.tomcat.util.threads)</li>
<li><strong><font color="red">ThreadPoolExecutor</font></strong> (java.util.concurrent)

<ul>
<li>ScheduledThreadPoolExecutor (java.util.concurrent)

<ul>
<li>UnorderedThreadPoolEventExecutor (io.netty.util.concurrent)</li>
</ul></li>
</ul></li>
</ul></li>
<li>ScheduledExecutorService (java.util.concurrent)

<ul>
<li>DelegatedScheduledExecutorService in Executors (java.util.concurrent)</li>
<li>EventExecutorGroup (io.netty.util.concurrent)

<ul>
<li>AbstractEventExecutorGroup (io.netty.util.concurrent)

<ul>
<li>AbstractEventLoopGroup (io.netty.channel)</li>
<li>MultithreadEventExecutorGroup (io.netty.util.concurrent)

<ul>
<li>DefaultEventExecutorGroup (io.netty.util.concurrent)</li>
<li>MultithreadEventLoopGroup (io.netty.channel)

<ul>
<li>DefaultEventLoopGroup (io.netty.channel)

<ul>
<li>LocalEventLoopGroup (io.netty.channel.local)</li>
</ul></li>
<li>NioEventLoopGroup (io.netty.channel.nio)</li>
</ul></li>
</ul></li>
<li>ThreadPerChannelEventLoopGroup (io.netty.channel)

<ul>
<li>OioEventLoopGroup (io.netty.channel.oio)</li>
</ul></li>
</ul></li>
<li>EventExecutor (io.netty.util.concurrent)

<ul>
<li>AbstractEventExecutor (io.netty.util.concurrent)

<ul>
<li>AbstractEventLoop (io.netty.channel)</li>
<li>AbstractScheduledEventExecutor (io.netty.util.concurrent)

<ul>
<li>EmbeddedEventLoop (io.netty.channel.embedded)</li>
<li>GlobalEventExecutor (io.netty.util.concurrent)</li>
<li>SingleThreadEventExecutor (io.netty.util.concurrent)

<ul>
<li>DefaultEventExecutor (io.netty.util.concurrent)</li>
<li>SingleThreadEventLoop (io.netty.channel)

<ul>
<li>DefaultEventLoop (io.netty.channel)</li>
<li>NioEventLoop (io.netty.channel.nio)</li>
<li>ThreadPerChannelEventLoop (io.netty.channel)</li>
</ul></li>
</ul></li>
</ul></li>
<li>ImmediateEventExecutor (io.netty.util.concurrent)</li>
<li>NonStickyOrderedEventExecutor in NonStickyEventExecutorGroup (io.netty.util.concurrent)</li>
</ul></li>
<li>OrderedEventExecutor (io.netty.util.concurrent)

<ul>
<li>EventLoop (io.netty.channel)

<ul>
<li>AbstractEventLoop (io.netty.channel)</li>
<li>EmbeddedEventLoop (io.netty.channel.embedded)</li>
<li>SingleThreadEventLoop (io.netty.channel)

<ul>
<li>DefaultEventLoop (io.netty.channel)</li>
<li>NioEventLoop (io.netty.channel.nio)</li>
<li>ThreadPerChannelEventLoop (io.netty.channel)</li>
</ul></li>
</ul></li>
<li>NonStickyOrderedEventExecutor in NonStickyEventExecutorGroup (io.netty.util.concurrent)</li>
<li>SingleThreadEventExecutor (io.netty.util.concurrent)

<ul>
<li>DefaultEventExecutor (io.netty.util.concurrent)</li>
<li>SingleThreadEventLoop (io.netty.channel)

<ul>
<li>DefaultEventLoop (io.netty.channel)</li>
<li>NioEventLoop (io.netty.channel.nio)</li>
<li>ThreadPerChannelEventLoop (io.netty.channel)</li>
</ul></li>
</ul></li>
</ul></li>
<li>UnorderedThreadPoolEventExecutor (io.netty.util.concurrent)</li>
</ul></li>
<li>EventLoopGroup (io.netty.channel)

<ul>
<li>AbstractEventLoopGroup (io.netty.channel)</li>
<li>EventLoop (io.netty.channel)

<ul>
<li>AbstractEventLoop (io.netty.channel)</li>
<li>EmbeddedEventLoop (io.netty.channel.embedded)</li>
<li>SingleThreadEventLoop (io.netty.channel)

<ul>
<li>DefaultEventLoop (io.netty.channel)</li>
<li>NioEventLoop (io.netty.channel.nio)</li>
<li>ThreadPerChannelEventLoop (io.netty.channel)</li>
</ul></li>
</ul></li>
<li>MultithreadEventLoopGroup (io.netty.channel)

<ul>
<li>DefaultEventLoopGroup (io.netty.channel)

<ul>
<li>LocalEventLoopGroup (io.netty.channel.local)</li>
</ul></li>
<li>NioEventLoopGroup (io.netty.channel.nio)</li>
</ul></li>
<li>ThreadPerChannelEventLoopGroup (io.netty.channel)

<ul>
<li>OioEventLoopGroup (io.netty.channel.oio)</li>
</ul></li>
</ul></li>
<li>NonStickyEventExecutorGroup (io.netty.util.concurrent)</li>
</ul></li>
<li>ScheduledThreadPoolExecutor (java.util.concurrent)

<ul>
<li>UnorderedThreadPoolEventExecutor (io.netty.util.concurrent)</li>
</ul></li>
<li>ScheduledThreadPoolExecutor (org.apache.tomcat.util.threads)</li>
<li>UnsupportedScheduledExecutorService in DelegateServiceScheduler (reactor.core.scheduler)</li>
</ul></li>
</ul></li>
<li>ImmediateExecutor (io.netty.util.concurrent)</li>
<li>ResizableExecutor (org.apache.tomcat.util.threads)

<ul>
<li>StandardThreadExecutor (org.apache.catalina.core)</li>
</ul></li>
<li>SingleWorkerScheduler (reactor.core.scheduler)</li>
<li>TaskExecutor (org.springframework.core.task)

<ul>
<li>AsyncTaskExecutor (org.springframework.core.task)

<ul>
<li>AsyncListenableTaskExecutor (org.springframework.core.task)

<ul>
<li>ConcurrentTaskExecutor (org.springframework.scheduling.concurrent)

<ul>
<li>ConcurrentTaskScheduler (org.springframework.scheduling.concurrent)

<ul>
<li>DefaultManagedTaskScheduler (org.springframework.scheduling.concurrent)</li>
</ul></li>
<li>DefaultManagedTaskExecutor (org.springframework.scheduling.concurrent)</li>
</ul></li>
<li>SimpleAsyncTaskExecutor (org.springframework.core.task)</li>
<li>SimpleThreadPoolTaskExecutor (org.springframework.scheduling.quartz)</li>
<li>TaskExecutorAdapter (org.springframework.core.task.support)

<ul>
<li>ManagedTaskExecutorAdapter in ConcurrentTaskExecutor (org.springframework.scheduling.concurrent)</li>
</ul></li>
<li>ThreadPoolTaskExecutor (org.springframework.scheduling.concurrent)</li>
<li>ThreadPoolTaskScheduler (org.springframework.scheduling.concurrent)</li>
<li>WorkManagerTaskExecutor (org.springframework.jca.work)</li>
<li>WorkManagerTaskExecutor (org.springframework.scheduling.commonj)</li>
</ul></li>
<li>SchedulingTaskExecutor (org.springframework.scheduling)

<ul>
<li>ConcurrentTaskExecutor (org.springframework.scheduling.concurrent)

<ul>
<li>ConcurrentTaskScheduler (org.springframework.scheduling.concurrent)

<ul>
<li>DefaultManagedTaskScheduler (org.springframework.scheduling.concurrent)</li>
</ul></li>
<li>DefaultManagedTaskExecutor (org.springframework.scheduling.concurrent)</li>
</ul></li>
<li>SimpleThreadPoolTaskExecutor (org.springframework.scheduling.quartz)</li>
<li>ThreadPoolTaskExecutor (org.springframework.scheduling.concurrent)</li>
<li>ThreadPoolTaskScheduler (org.springframework.scheduling.concurrent)</li>
<li>WorkManagerTaskExecutor (org.springframework.jca.work)</li>
<li>WorkManagerTaskExecutor (org.springframework.scheduling.commonj)</li>
</ul></li>
</ul></li>
<li>SyncTaskExecutor (org.springframework.core.task)</li>
</ul></li>
<li>ThreadPerTaskExecutor (io.netty.util.concurrent)</li>
<li>ThreadPerTaskExecutor in CompletableFuture (java.util.concurrent)</li>
</ul>

<p><strong>ThreadPoolExecutor 的类构造如下：</strong></p>

<p><img src="/hugo/src/img/java/threadPoolExecutor.png" /></p>

<p><strong>Executors 的类构造如下</strong></p>

<p><img src="/hugo/src/img/java/executors.png" /></p>
                        </div>

                        


                        

<div class="post-archive">
    <h2>See Also</h2>
    <ul class="listing">
        
        <li><a href="/hugo/post/java/thinking_in_java/%E7%AC%AC%E4%BA%8C%E5%8D%81%E7%AB%A0-%E6%B3%A8%E8%A7%A3/">第二十章 注解</a></li>
        
        <li><a href="/hugo/post/java/thinking_in_java/%E7%AC%AC%E5%8D%81%E5%85%AB%E7%AB%A0-java-io%E7%B3%BB%E7%BB%9F/">第十八章 Java IO系统</a></li>
        
        <li><a href="/hugo/post/java/thinking_in_java/%E7%AC%AC%E5%8D%81%E4%B8%83%E7%AB%A0-%E5%AF%B9%E8%B1%A1%E7%9A%84%E5%AE%B9%E7%BA%B3-%E5%AE%B9%E5%99%A8/">第十七章 对象的容纳-容器</a></li>
        
        <li><a href="/hugo/post/java/thinking_in_java/%E7%AC%AC%E5%85%AB%E7%AB%A0-%E5%A4%9A%E6%80%81%E6%80%A7/">第八章 多态性</a></li>
        
        <li><a href="/hugo/post/java/thinking_in_java/%E7%AC%AC%E4%B8%83%E7%AB%A0-%E7%B1%BB%E5%A4%8D%E7%94%A8/">第七章 类复用</a></li>
        
    </ul>
</div>


                        <div class="post-meta meta-tags">
                            
                            <ul class="clearfix">
                                
                                <li><a href="https://otswang.gitee.io/hugo/tags/java">Java</a></li>
                                
                                <li><a href="https://otswang.gitee.io/hugo/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B">多线程</a></li>
                                
                            </ul>
                            
                        </div>
                    </article>
                    
    

    
    
                </div>
            </div>
            <div id="secondary">

    <section class="widget">
        <form id="search" action="//www.google.com/search" method="get" accept-charset="utf-8" target="_blank" _lpchecked="1">
      
      <input type="text" name="q" maxlength="20" placeholder="Search">
      <input type="hidden" name="sitesearch" value="https://otswang.gitee.io/hugo/">
      <button type="submit" class="submit icon-search"></button>
</form>
    </section>

    
    <div class="clear">
        <div class="toc-article">
            <div class="toc-title">文章目录</dixsv>
            <nav id="TableOfContents">
<ul>
<li>
<ul>
<li><a href="#概览">概览</a></li>
<li><a href="#volatile关键字">volatile关键字</a></li>
<li><a href="#主要工具">主要工具</a>
<ul>
<li><a href="#threadlocal">ThreadLocal</a></li>
<li><a href="#原子类">原子类</a></li>
<li><a href="#lock">Lock</a></li>
<li><a href="#容器类">容器类</a></li>
<li><a href="#管理类">管理类</a></li>
</ul></li>
<li><a href="#深入浅出java-concurrent-学习">深入浅出Java concurrent 学习</a></li>
<li><a href="#原子操作">原子操作</a></li>
<li><a href="#线程安全的实现方法">线程安全的实现方法</a></li>
<li><a href="#synchronized-关键字"><code>synchronized</code>关键字</a></li>
<li><a href="#悲观锁与乐观锁">悲观锁与乐观锁</a></li>
<li><a href="#偏向锁-轻量级锁和重量级锁以及锁优化">偏向锁、轻量级锁和重量级锁以及锁优化</a></li>
<li><a href="#线程池">线程池</a>
<ul>
<li><a href="#线程池参数">线程池参数</a></li>
<li><a href="#问题">问题</a></li>
<li><a href="#为什么不建议使用executors创建线程池">为什么不建议使用Executors创建线程池？</a></li>
</ul></li>
<li><a href="#executor与threadpoolexecutor的使用">Executor与ThreadPoolExecutor的使用</a></li>
</ul></li>
</ul>
</nav>
        </div>
    </div>
    

</div>
        </div>
    </div>
</div>
<footer id="footer">
    <div class="container">
        &copy; 2020 <a href="https://otswang.gitee.io/hugo/">The Sky of OtsWang By OtsWang</a>.
        Powered by <a rel="nofollow noreferer noopener" href="https://gohugo.io" target="_blank">Hugo</a>.
        <a href="https://www.flysnow.org/" target="_blank">Theme</a> based on <a href="https://github.com/Dudiao137/maupassant-hugo" target="_blank">maupassant-ots</a>.
        
    </div>
</footer>


    <script type="text/javascript">
    
    (function(){
        $("pre code").parent().addClass("line-numbers")
    }())

    window.MathJax = {
        tex2jax: {
            inlineMath: [ ['$','$'] ],
            processEscapes: true
        }
    };
    </script>
    <script type="text/javascript" src="/hugo/js/prism.js" async="true"></script>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML' async></script>

<a id="rocket" href="#top"></a>
<script type="text/javascript" src="/hugo/js/totop.js?v=0.0.0" async=""></script>







 
 <script src="https://mermaidjs.github.io/scripts/mermaid.min.js"></script>
 <script>
       mermaid.initialize({ startOnLoad: true });
 </script>
</body>
</html>
